using System;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Data;

namespace UDS.Management.Data.Package
{
    /// <summary>
    /// Loads, validates, and serializes the XML replication file from disk or from the specified assembly
    /// </summary>
    public class ReplXMLHelper
    {
		private XmlReaderSettings readerSettings = null;
        private Stream XsdStream = null;

		public ReplXMLHelper()
		{
            XsdStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(SCHEMA_REPLICATION_NAME);
            using (XmlTextReader replXsdReader = new XmlTextReader(XsdStream))
            {
                readerSettings = new XmlReaderSettings();
                readerSettings.ValidationType = ValidationType.Schema;
                readerSettings.Schemas.ValidationEventHandler += new ValidationEventHandler(ReaderSettings_ValidationEventHandler);
                readerSettings.ValidationEventHandler += new ValidationEventHandler(ReaderSettings_ValidationEventHandler);
                readerSettings.Schemas.Add("http://www.sosceo.com/server/Install/DBReplication", replXsdReader);
                replXsdReader.Close();
            }
		}
		

        /// <summary>
        /// The name of the replication xsd file in the assembly
        /// </summary>
        private const string SCHEMA_REPLICATION_NAME = "UDS.Management.Data.ReplXMLSchemas.xsd";

		/// <summary>
		/// Load the DB Replication definition file from the assembly loader
		/// </summary>
		/// <exception cref="Exceptions.PackageValidationException">A PackageValidationException is thrown if the manifest does not match the schema</exception>
        /// <param name="replicationDefinitionStream">The manifest stream to validate</param>
		/// <returns>A database manifest object</returns>
        public Publication Load(ScriptSource source)
		{			
			// Now serialize the manifest
            using (XmlReader ValidatingReader = XmlTextReader.Create(source.Stream, readerSettings))
			{
				try
				{
					// Deserialize the stream
					XmlSerializer Serializer = new XmlSerializer(typeof(Publication));

                    return (Publication)Serializer.Deserialize(ValidatingReader);
				}
				catch (InvalidOperationException ioEx)
				{
					// Treat the package validation exception specifically so callers
					// can differentiate between this and an unhandled exception
                    if (ioEx.InnerException is Exceptions.ReplicationValidationException)
					{
                        Exceptions.ReplicationValidationException ReplicationEx = ioEx.InnerException as Exceptions.ReplicationValidationException;
                        ReplicationEx.PackageName = source.Name;
                        throw ReplicationEx;
					}
					else
					{
						throw;
					}
				}
			}
		}

        private void ReaderSettings_ValidationEventHandler(object sender, ValidationEventArgs e)
        {
			if (e.Severity == XmlSeverityType.Error)
			{
				string Message = e.Message.TrimEnd('.');
                Exceptions.ReplicationValidationException ex = new Exceptions.ReplicationValidationException(String.Format("{0} at line {1}, position {2}.", Message, e.Exception.LineNumber, e.Exception.LinePosition));
				throw ex;
			}
        }
	}
}
